#ifndef SWOOLE_H_
#define SWOOLE_H_

#if defined(HAVE_CONFIG_H) && !defined(COMPILE_DL_MYSERVER)
#include "config.h"
#endif

#ifdef SW_STATIC_COMPILATION
#include "php_config.h"
#endif

#include <assert.h>
#include <ctype.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include <signal.h>
#include <time.h>
#include <limits.h>

#include <fcntl.h>
#include <unistd.h>
#include <pthread.h>
#if defined(HAVE_CPU_AFFINITY)
#ifdef __FreeBSD__
#include <sys/types.h>
#include <sys/cpuset.h>
#include <pthread_np.h>
typedef cpuset_t cpu_set_t;
#else
#include <sched.h>
#endif
#endif

#include <arpa/inet.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <netdb.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <sys/select.h>
#include <sys/mman.h>
#include <sys/ipc.h>
#include <sys/wait.h>
#include <sys/un.h>
#include <sys/types.h>
#include <sys/utsname.h>

#include "swoole_config.h"

#define SW_MAX_FDTYPE          32

//------lock----
enum SW_LOCKS
{
	SW_RWLOCK = 1,
#define SW_RWLOCK SW_RWLOCK
	SW_FILELOCK = 2,
#define SW_FILELOCK SW_FILELOCK
	SW_MUTEX = 3,
#define SW_MUTEX SW_MUTEX
	SW_SEM = 4,
#define SW_SEM SW_SEM
	SW_SPINLOCK = 5,
#define SW_SPINLOCK SW_SPINLOCK
	SW_ATOMLOCK = 6,
#define SW_ATOMLOCK SW_ATOMLOCK
};

#if defined(__GNUC__)
#if __GNUC__ >= 3
#define sw_inline inline __attribute__((always_inline))
#else
#define sw_inline inline
#endif
#elif defined(_MSC_VER)
#define sw_inline __forceinline
#else
#define sw_inline inline
#endif

typedef struct _swMutex{
	pthread_mutex_t _lock;
	pthread_mutexattr_t attr;
}swMutex;

typedef struct _swLock{
	int type;
	union{
		swMutex mutex;
	} object;

	int (*lock_rd)(struct _swLock *);
	int (*lock)(struct _swLock *);
	int (*unlock)(struct _swLock *);
	int (*trylock_rd)(struct _swLock *);
	int (*trylock)(struct _swLock *);
	int (*free)(struct _swLock *);
} swLock;

int swMutex_create(swLock *lock,int use_in_process);

typedef struct _swMemoryPool{
	void *object;
	void *(*alloc)(struct _swMemoryPool *pool,uint32_t size);
	void (*free)(struct _swMemoryPool *pool,void *ptr);
	void (*destroy)(struct _swMemoryPool *pool);
}swMemoryPool;

typedef struct _swFactory swFactory;
typedef struct _swServer swServer;
typedef struct _swReactor swReactor;

typedef struct{
	int running;
	swReactor *main_reactor;
	pid_t pid;
	swMemoryPool *memory_pool;
	swFactory *factory;
	swServer *serv;
	uint16_t cpu_num;
	uint8_t use_signalfd;
	int signal_fd;
} swServerG;

typedef struct _swShareMemory_mmap{
	size_t size;
	void *mem;
}swShareMemory;

extern swServerG SwooleG;
void *swShareMemory_mmap_create(swShareMemory *object,size_t size);
void swShareMemory_mmap_free(swShareMemory *object);
void* sw_shm_malloc(size_t size);
void* sw_shm_calloc(size_t num, size_t _size);
void sw_shm_free(void *ptr);

swMemoryPool* swMemoryGlobal_new(uint32_t pagesize,uint8_t shared);

typedef struct
{
	uint32_t id;
	uint32_t fd :24;
	uint32_t reactor_id :8;
} swSession;

typedef struct _swConnection{
	uint8_t removed;
	void *object;
	int fd;
	int from_id;
	uint32_t from_fd;
	uint8_t connect_notify;
	uint32_t session_id;
	
	//system fd listen sock,signalfd must be 0
	uint8_t active;
}swConnection;

typedef struct _swDataHead{
	int fd;
    uint16_t len;
    int16_t from_id;
    uint8_t type;
    uint8_t flags;
    uint16_t from_fd;
}swDataHead;

typedef struct _swEvent{
	int fd;
	int16_t from_id;
	uint8_t type;
	swConnection *socket;
}swEvent;

typedef struct _swEventData
{
	swDataHead info;
	char data[SW_BUFFER_SIZE];
} swEventData;

typedef struct _swSendData
{
	swDataHead info;
	/**
     * for big package
     */
	uint32_t length;
	char *data;
} swSendData;

typedef int (*swReactor_handle)(swReactor *reactor, swEvent *event);
typedef void (*swSignalHander)(int);
int swReactor_onWrite(swReactor *reactor, swEvent *ev);
//------pipe------
typedef struct _swPipe
{
    void *object;
    int blocking;
    double timeout;

    int (*read)(struct _swPipe *, void *recv, int length);
    int (*write)(struct _swPipe *, void *send, int length);
    int (*getFd)(struct _swPipe *, int master);
    int (*close)(struct _swPipe *);
} swPipe;

int swPipeUnsock_create(swPipe *p, int blocking, int protocol);

struct _swReactor{
	void *object;
	void *ptr;  //reserve

	uint32_t running;
	uint32_t event_num;
	uint32_t start;
	uint32_t thread;
	uint32_t max_event_num;

	uint16_t id; //Reactor ID

	int32_t timeout_msec;

	//for thread
	swConnection *socket_list;
	uint32_t max_socket;

	swReactor_handle handle[SW_MAX_FDTYPE];        //默认事件
    swReactor_handle write_handle[SW_MAX_FDTYPE];  //扩展事件1(一般为写事件)
	swReactor_handle error_handle[SW_MAX_FDTYPE];  //扩展事件2(一般为错误事件,如socket关闭)

	int (*add)(swReactor *, int fd, int fdtype);
	int (*set)(swReactor *, int fd, int fdtype);
	int (*del)(swReactor *, int fd);
	int (*wait)(swReactor *, struct timeval *);
	void (*free)(swReactor *);

	int (*setHandle)(swReactor *, int fdtype, swReactor_handle);
	int (*close)(swReactor *, int);
	int (*write)(swReactor *, int, void *, int);
};

typedef struct _swWorker swWorker;
typedef struct _swProcessPool swProcessPool;
struct _swWorker{
	pid_t pid;
	int pipe_master;
	int pipe_worker;
	swPipe *pipe_object;
	swProcessPool *pool;
};

typedef struct {
	swWorker *worker;
}swWorkerG;

extern swWorkerG SwooleWG;

struct _swProcessPool{
	swWorker *workers;
	int worker_num;
};

void swoole_fcntl_set_option(int sock, int nonblock, int cloexec);

#ifdef SW_USE_IOCTL
#define swSetNonBlock(sock)   swoole_ioctl_set_block(sock, 1)
#define swSetBlock(sock)      swoole_ioctl_set_block(sock, 0)
#else
#define swSetNonBlock(sock)   swoole_fcntl_set_option(sock, 1, -1)
#define swSetBlock(sock)      swoole_fcntl_set_option(sock, 0, -1)
#endif

enum swFd_type
{
    SW_FD_TCP             = 0, //tcp socket
    SW_FD_LISTEN          = 1, //server socket
    SW_FD_CLOSE           = 2, //socket closed
    SW_FD_ERROR           = 3, //socket error
    SW_FD_UDP             = 4, //udp socket
    SW_FD_PIPE            = 5, //pipe
    SW_FD_STREAM          = 6, //stream socket
    SW_FD_WRITE           = 7, //fd can write
    SW_FD_TIMER           = 8, //timer fd
    SW_FD_AIO             = 9, //linux native aio
    SW_FD_SIGNAL          = 11, //signalfd
    SW_FD_DNS_RESOLVER    = 12, //dns resolver
    SW_FD_INOTIFY         = 13, //server socket
    SW_FD_USER            = 15, //SW_FD_USER or SW_FD_USER+n: for custom event
    SW_FD_STREAM_CLIENT   = 16, //swClient stream
    SW_FD_DGRAM_CLIENT    = 17, //swClient dgram
};

enum swEvent_type
{
    SW_EVENT_DEAULT = 256,
    SW_EVENT_READ = 1u << 9,
    SW_EVENT_WRITE = 1u << 10,
    SW_EVENT_ERROR = 1u << 11,
    SW_EVENT_ONCE = 1u << 12,
};

typedef struct _swThreadParam
{
	void *object;
	int pti;
} swThreadParam;

int swReactor_create(swReactor *reactor, int max_event);
int swReactor_setHandle(swReactor *, int, swReactor_handle);
int swSocket_bind(int sock, char *host, int *port);
int swReactor_write(swReactor *reactor, int fd, void *buf, int n);

static sw_inline int swReactor_event_read(int fdtype)
{
    return (fdtype < SW_EVENT_DEAULT) || (fdtype & SW_EVENT_READ);
}

static sw_inline int swReactor_event_write(int fdtype)
{
    return fdtype & SW_EVENT_WRITE;
}

static sw_inline int swReactor_event_error(int fdtype)
{
    return fdtype & SW_EVENT_ERROR;
}

static sw_inline int swReactor_fdtype(int fdtype)
{
    return fdtype & (~SW_EVENT_READ) & (~SW_EVENT_WRITE) & (~SW_EVENT_ERROR);
}

static sw_inline swReactor_handle swReactor_getHandle(swReactor *reactor, int event_type, int fdtype)
{
    if (event_type == SW_EVENT_WRITE)
    {
        return (reactor->write_handle[fdtype] != NULL) ? reactor->write_handle[fdtype] : reactor->handle[SW_FD_WRITE];
    }
    else if (event_type == SW_EVENT_ERROR)
    {
        return (reactor->error_handle[fdtype] != NULL) ? reactor->error_handle[fdtype] : reactor->handle[SW_FD_CLOSE];
    }
    return reactor->handle[fdtype];
}

static sw_inline int swWaitpid(pid_t __pid, int *__stat_loc, int __options)
{
    int ret;
    do
    {
        ret = waitpid(__pid, __stat_loc, __options);
        if (ret < 0 && errno == EINTR)
        {
            continue;
        }
        break;
    } while(1);
    return ret;
}

static sw_inline int swKill(pid_t __pid, int __sig)
{
    int ret;
    do
    {
        ret = kill(__pid, __sig);
        if (ret < 0 && errno == EINTR)
        {
            continue;
        }
        break;
    } while (1);
    return ret;
}

/*
static sw_inline swConnection* swReactor_get(swReactor *reactor, int fd){
	//do not think of buffer
	swServer *serv = reactor->ptr;

	return &serv->connection_list[fd];
}
*/

/*
static sw_inline swConnection* swReactor_get(swReactor *reactor, int fd){
	//if (reactor->thread)
	//{
		return &reactor->socket_list[fd];
	//}
}
*/

#endif//SWOOLE_H_
